#include "HTTPDownload.h"

//#include <QtCore>
#include <QtNetwork>
#include <QDir>

HTTPDownload::HTTPDownload(QObject *parent) :
    QNetworkAccessManager(parent)
{
    m_bHttpRequestAbort = false;
    connect(this, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
}


HTTPDownload::~HTTPDownload()
{

}

bool HTTPDownload::checkURL(QUrl url)
{
    if (!url.isValid())
    {
        qCritical() << "[!ERROR]: Invalid URL";
        return false;
    }

    if (url.scheme() == "http" || url.scheme() == "https")
    {
        if(url.scheme() == "https")
        {
            QSslConfiguration config = m_NetWorkRequest.sslConfiguration();
            config.setPeerVerifyMode(QSslSocket::VerifyNone);
            config.setProtocol(QSsl::TlsV1SslV3);
            m_NetWorkRequest.setSslConfiguration(config);
        }
    }
    else
    {
        qCritical() << "[!ERROR]: URL must start with 'http/https:'" << url.scheme();
        return false;
    }

    if (url.path().isEmpty()) {
        qCritical() << "[!ERROR]: URL has no path";
        return false;
    }
    //url.host(), url.port(80)

    qDebug() << "request header:" << m_NetWorkRequest.rawHeaderList();

    return true;
}

bool HTTPDownload::download(QUrl url, QString localpathfile, bool writeToFile)
{
    if(!checkURL(url))
        return false;

    m_baHttpData.clear();
    if(writeToFile) //写入文件
    {
        m_nWriteType = 1;

        QFileInfo fileInfo = "." + url.path();
        //file = new QFile(fileInfo.fileName());

        if(localpathfile.isEmpty())
            m_strLocalFilePathName = fileInfo.absoluteFilePath(); // QFileInfo(url.path()).fileName();
        else
        {
            m_strLocalFilePathName = localpathfile;
            fileInfo.setFile(m_strLocalFilePathName);
        }

        if (m_strLocalFilePathName.isEmpty())
        {
            m_strLocalFilePathName = "HTTPDownload.out";
            fileInfo.setFile(m_strLocalFilePathName);
        }


/*
        qDebug() << "path:" << url.path();
        qDebug() << "filePath:" << fileInfo.filePath();
        qDebug() << "absoluteFilePath:" << fileInfo.absoluteFilePath();
        qDebug() << "canonicalFilePath:" << fileInfo.canonicalFilePath();
        qDebug() << "baseName:" << fileInfo.baseName();
        qDebug() << "completeBaseName:" << fileInfo.completeBaseName();
        qDebug() << "suffix:" << fileInfo.suffix();
        qDebug() << "bundleName:" << fileInfo.bundleName();
        qDebug() << "completeSuffix:" << fileInfo.completeSuffix();
        qDebug() << "path:" << fileInfo.path();
        qDebug() << "absolutePath:" << fileInfo.absolutePath();
        qDebug() << "canonicalPath:" << fileInfo.canonicalPath();
        qDebug() << "dir:" << fileInfo.dir();
        qDebug() << "absoluteDir:" << fileInfo.absoluteDir();
*/

        QString m_strDir = fileInfo.absolutePath();//文件的存储位置
        if( !m_strDir.isEmpty() )//文件夹
        {
            QDir directory( m_strDir );
            if( !directory.exists() )//没有此文件夹，则创建
            {
                if(!directory.mkpath( m_strDir ))
                {
                    qCritical() << "[!ERROR]fail make path";
                    return false;
                }
            }
            //m_strFileName = m_strDir + "/"+m_strFileName;//添加/是为了防止用户名没有加/，因为对于文件夹来说两个/都会当成一个/
        }
        qDebug() << "HTTPDownload::download filepath:" << m_strDir;

    }
    else
        m_nWriteType = 0;

    m_NetWorkRequest.setUrl(url);
    /******************设置http的header***********************/
    // request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
    // request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
    // request.setRawHeader("Content-Disposition","form-data;name='doc';filename='a.txt'");
    //request.setHeader(QNetworkRequest::ContentLengthHeader,post_data.length());

    m_pNetWorkReply = this->get(m_NetWorkRequest);//通过发送数据，返回值保存在reply指针里.
    connect(m_pNetWorkReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT( onDownloadProgress(qint64 ,qint64 )));//download文件时进度
    connect(m_pNetWorkReply, SIGNAL(readyRead()),this, SLOT(onReadyRead()));
    connect(m_pNetWorkReply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT( onReplyError(QNetworkReply::NetworkError)) );//出现错误时发送此信号;

    return true;
}

void HTTPDownload::onReadyRead()
{
    if(m_pNetWorkReply->error() == QNetworkReply::NoError)
    {
        qDebug() << "HTTPDownload::onReadyRead: NoError";
        if(m_nWriteType == 1)  //写到文件
        {
            if(m_fileOut.isOpen())
            {
                qDebug() << "HTTPDownload::onReadyRead: File readed";
            }
            else
            {
                qDebug() << "HTTPDownload::onReadyRead: File Create:"<<m_strLocalFilePathName + ".tmp";
                m_fileOut.setFileName(m_strLocalFilePathName + ".tmp");
                if(!m_fileOut.open(QIODevice::WriteOnly))    //只读方式打开文件
                {
                    qCritical() << "[!ERROR]fail save file!";
                    stop();
                    return;
                }
            }
            m_fileOut.write(m_pNetWorkReply->readAll());
        }
        else
            m_baHttpData.append(m_pNetWorkReply->readAll());
    }
    else
    {
        stop();
        qCritical() << "[!ERROR]HTTPDownload::onReadyRead";
    }
    //qDebug() << m_baHttpData;
}


/***************响应结束**************************/
void HTTPDownload::onFinished(QNetworkReply *reply){

    if(m_nWriteType == 1)
    {
        if(m_fileOut.isOpen())
        {
            m_fileOut.flush();
            m_fileOut.close();
        }
        else
        {
            qWarning() << "[!Warning]HTTPDownload::onFinished:Download To 0 Byte File!" << m_strLocalFilePathName + ".tmp";

            m_fileOut.setFileName(m_strLocalFilePathName + ".tmp");
            if(!m_fileOut.open(QIODevice::WriteOnly))    //只读方式打开文件
            {
                qCritical() << "[!ERROR]fail save file!";
                stop();
                return;
            }
            m_fileOut.flush();
            m_fileOut.close();
        }
    }


    //获取响应的信息，状态码为200表示正常
    QVariant status_code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

    //无错误返回
    if(reply->error() == QNetworkReply::NoError && status_code == 200)
    {
        if(m_nWriteType == 1)
        {
            if( QFile::exists(m_strLocalFilePathName) )//如果文件已经存在，那么删除
            {
                if(!QFile::remove(m_strLocalFilePathName))
                {
                    if(!QFile::rename(m_strLocalFilePathName, "~" + m_strLocalFilePathName + ".old"))
                        qCritical() << "[!ERROR]Del Old File Error";
                }
            }
            if(!QFile::rename(m_strLocalFilePathName + ".tmp", m_strLocalFilePathName))
                qCritical() << "[!ERROR]Rename File Error";
        }

        qDebug() << "Your thing had finished downloading.";
        emit s_finished(reply);
    }
    else
    {
        if(m_nWriteType == 1)
        {
            if( QFile::exists(m_strLocalFilePathName + ".tmp") )//如果文件已经存在，那么删除
            {
                if(!QFile::remove(m_strLocalFilePathName + ".tmp"))
                    qCritical() << "[!ERROR]Remove Temp File Error";
            }
        }

        //处理错误
        qCritical() << "[!ERROR]HTTPDownload::onFinished: download Error!!!" << status_code << reply->error();
        emit s_finished(reply);
    }

    reply->deleteLater();//要删除reply，但是不能在onFinished里直接delete，要调用deletelater;
    //pReply = nullptr;
}

void HTTPDownload::onDownloadProgress(qint64 a,qint64 b)
{
    //file.write(reply->readAll());
    qDebug() << "HTTPDownload::onDownloadProgress:" << a << "/" << b;
}

void HTTPDownload::onReplyError(QNetworkReply::NetworkError e)
{
    qCritical() << "[!ERROR]HTTPDownload::onReplyError:" << e;
}

void HTTPDownload::stop()
{
    if(!m_bHttpRequestAbort)
    {
        m_pNetWorkReply->abort();//响应终止
        m_bHttpRequestAbort = true;
        qDebug() << "停止下载1";
    }
    else
    {   //HTTPDownload();
        m_bHttpRequestAbort = false;
        qDebug() << "停止下载2";
    }
}
